package com.wm;

/**
 * @ClassName:ArrayList
 * @Description: 实现ArrayList
 * @Author:Deamer
 * @Date:2022/1/2 21:43
 **/
public class ArrayList<E> extends AbstractList<E> {
    // 初始化容量大小
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 所有元素
     */
    private E[] elements;

    public ArrayList() {
        this(DEFAULT_CAPACITY);
    }

    public ArrayList(int capacity) {
        capacity = capacity < DEFAULT_CAPACITY ? DEFAULT_CAPACITY : capacity;
        elements = (E[]) new Object[capacity];
    }

    /**
     * 清除所有元素
     * 将size=0。为什么不将elements=null呢？这种做法不会浪费空间吗？不是的，不销毁内存表示我们下次可以重复利用，初始化的时候会有一个固定的数组大小，也就是提前向堆空间申请内存。
     * 假如把list的空间都释放掉，那么下一次，再去使用list的时候会向堆空间重新申请内存空间，我们知道销毁内存和向堆空间重新申请内存空间是很浪费性能的。所以说清掉才是浪费性能。
     */
    public void clear() {
        for (int i = 0; i < size; i++) {
            elements[i] = null;
        }
        size = 0;
    }

    /**
     * 查看元素索引
     *
     * @param element
     * @return
     */
    public int indexOf(E element) {
        // 对象的null处理
        if (null == element) {
            for (int i = 0; i < size; i++) {
                if (null == elements[i]) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                // 对象重写equals方法
                if (element.equals(elements[i])) {
                    return i;
                }
            }
        }
        return ELEMENT_NOT_FIND;
    }

    /**
     * 获取index位置的元素
     */
    public E get(int index) {
        rangeCheck(index);
        return elements[index];
    }

    /**
     * 设置index位置的元素
     *
     * @param index
     * @param element
     * @return
     */
    @Override
    public E set(int index, E element) {
        rangeCheck(index);
        E old = elements[index];
        elements[index] = element;
        return old;
    }

    /**
     * 在index位置插入一个元素
     *
     * @param index
     * @param element
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        // 扩容方法
        ensureCapacity(size + 1);
        for (int i = size; i > index; i--) {
            elements[i] = elements[i - 1];
        }
        elements[index] = element;
        size++;
    }

    /**
     * 数组扩容
     *
     * @param capacity
     */
    private void ensureCapacity(int capacity) {
        int oldCapacity = elements.length;
        if (oldCapacity >= capacity) return;
        // 扩容原来的1.5倍，选用位移的原因：*1.5是浮点数计算，浮点数计算比整数运算和位运算是耗时间的。
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        E[] newElements = (E[]) new Object[newCapacity];
        // 使用系统自带的System.arraycopy()效率会更高
        for (int i = 0; i < size; i++) {
            newElements[i] = elements[i];
        }
        elements = newElements;
        System.out.println(oldCapacity + "扩容为：" + newCapacity);
    }

    /**
     * 删除index位置的元素
     */
    public E remove(int index) {
        rangeCheck(index);
        E old = elements[index];
        for (int i = index + 1; i < size; i++) {
            elements[i - 1] = elements[i];
        }
        // remove移动之后，最后一个元素被前移到前一位，那么这时候最后一个元素存的是还是之前的地址，所以需要置空。
        elements[--size] = null;
        return old;
    }


    @Override
    public String toString() {
        // size=3,[22,33,44,55]
        StringBuilder string = new StringBuilder("size=");
        string.append(size).append(", [");
        for (int i = 0; i < size; i++) {
            if (i != 0) {
                string.append(",");
            }
            string.append(elements[i]);
            // 这种还需要计算一次减1
         /*   if (i != size - 1) {
                string.append(",");
            }*/
        }
        string.append("]");
        return string.toString();
    }
}
